﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OrderAggregator.InputFormats.Ashan
{
    /// <summary>
    /// "Ашан" формат
    /// </summary>
    public class AshanFormat : BaseOrderFormat
    {
        public readonly static AshanFormat Instance = new AshanFormat();

        private AshanFormat()
        {
        }
        
        /// <summary>
        /// Parse
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="getStream"></param>
        /// <returns></returns>
        public override BaseOrder Parse(string filePath, Func<System.IO.Stream> getStream)
        {
            if (!string.Equals(System.IO.Path.GetExtension(filePath), dotTXT, StringComparison.InvariantCultureIgnoreCase))
            {
                return null;
            }

            var lines = ReadLines(filePath);

            //это будет признак формата .txt
            //if (!lines.Any(ln => ln.Contains("AUCHAN")))
            if (!lines.Any(ln => ln.Contains("З А К А З А Н О")))
            {
                return null;
            }

            return Parse(lines);
        }

        private static BaseOrder Parse(string[] lines)
        {
            var pages = SplitToPages(lines);

            BaseOrder order = null;

            foreach (var pageLines in pages)
            {
                //для кадой страницы

                if (order == null)
                {
                    order = new BaseOrder();
                    order.Client = ParseClient(pageLines);
                    order.Id = ParseOrderId(pageLines);
                    order.ReceiveTime = ParseDate(pageLines);
                }

                var orderRowLines = GetOrderRowLines(pageLines);

                foreach (var orderRowLine in orderRowLines)
                {
                    var orderRow = ParseOrderRow(orderRowLine);
                    if (orderRow == null)
                    {
                        break;
                    }
                    order.OrderRows.Add(orderRow);
                }
            }

            return order;
        }

        /// <summary>
        /// Парсить дату
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        private static DateTime ParseDate(string[] lines)
        {
            const string Запланирован_дата_отгруз = "Запланирован.дата отгруз.:";

            foreach (var line in lines)
            {
                var pos = line.IndexOf(Запланирован_дата_отгруз);
                if (pos >= 0)
                {
                    var str = line.Substring(pos + Запланирован_дата_отгруз.Length);
                    str = str.Replace("!", "").Trim();
                    return DateTime.Parse(str, RuCulture);
                }
            }

            throw new Exception(string.Format("Поле \"{0}\" не найдено.", Запланирован_дата_отгруз));
        }

        /// <summary>
        /// Парсить поле Заказчика
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        private static string ParseClient(string[] lines)
        {
            if (lines == null || lines.Length < 2)
            {
                return string.Empty;
            }

            var line = lines[1];
            var words = line.Split(new [] { " " }, StringSplitOptions.RemoveEmptyEntries);

            if (words.Length < 2)
            {
                return string.Empty;
            }

            var city = words[1];

            return string.Format("АШАН ({0})", city);
        }

        /// <summary>
        /// Парсить Номер заказа
        /// </summary>
        /// <returns></returns>
        private static string ParseOrderId(string[] lines)
        {
            const string Заказ = "ЗАКАЗ";

            var headers = new string[] { "ПОСТАВЩИК", "РЫНОК", "СЕГМЕН", Заказ, "ДАТА" };

            string targetLine = null;

            for (int i = 4; i < lines.Length; i++)
            {
                var line = lines[i];

                var words = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

                if (words.Length >= 7 &&
                    words[1] == headers[0] &&
                    words[2] == headers[1] &&
                    words[3] == headers[2] &&
                    words[4] == headers[3] &&
                    words[5] == headers[4]
                    )
                {
                    targetLine = lines[i + 1];
                    break;
                }
            }

            if (targetLine == null)
            {
                return null;
            }

            {
                var words = targetLine.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                return words[4];
            }
        }

        /// <summary>
        /// Извлечь строки позиций заказа2
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        private static string[] GetOrderRowLines(string[] lines)
        {
            int startLine = -1;

            for (int i = 3; i < lines.Length; i++)
            {
                var line = lines[i];

                if (!IsSplitLine(line))
                {
                    continue;
                }

                if (i + 2 >= lines.Length)
                {
                    break;
                }

                var nextLine = lines[i + 1];

                if (!nextLine.Contains("НАМЕНОВАНИЕ ТОВАРА"))
                {
                    continue;
                }

                startLine = i + 3;
                break;
            }

            if (startLine < 0)
            {
                return null;
            }

            var orderRowLines = new List<string>();
            
            for (int i = startLine; i < lines.Length; i++)
            {
                var line = lines[i];

                if (IsSplitLine(line))
                {
                    break;
                }

                orderRowLines.Add(line.Trim());
            }

            return orderRowLines.ToArray();
        }

        /// <summary>
        /// Проверка что линия-сплиттер (!---!, !-+-!)
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private static bool IsSplitLine(string line)
        {
            if (string.IsNullOrEmpty(line))
            {
                return false;
            }

            line = line.Trim();

            if (!line.StartsWith("!") && !line.EndsWith("!"))
            {
                return false;
            }

            for (int i = 1; i + 1 < line.Length; i++)
            {
                var ch = line[i];
                if (ch != '-' && ch != '+')
                {
                    return false;
                }
            }

            return true;
        }

        private static IEnumerable<string[]> SplitToPages(string[] lines)
        {
            var pages = new List<string[]>();

            List<string> pageLines = null;
            
            foreach (var line in lines)
            {
                if (IsPageSeparatorLine(line))
                {
                    if (pageLines != null)
                    {
                        pages.Add(pageLines.ToArray());
                    }
                    pageLines = null;
                }
                else
                {
                     if (pageLines == null)
                     {
                         pageLines = new List<string>();
                     }
                     pageLines.Add(line);
                }
            }

            if (pageLines != null && pageLines.Count > 0)
            {
                pages.Add(pageLines.ToArray());
            }

            return pages;
        }

        private static bool IsPageSeparatorLine(string line)
        {
            if (string.IsNullOrEmpty(line))
            {
                return false;
            }
            for (int i = 0; i < line.Length; i++)
            {
                var ch = line[i];

                if (ch != '=' && ch != ' ')
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Парсить строку заказа
        /// </summary>
        /// <param name="orderRowLine"></param>
        /// <returns></returns>
        private static BaseOrderRow ParseOrderRow(string orderRowLine)
        {
            if (string.IsNullOrEmpty(orderRowLine))
            {
                return null;
            }

            var words = orderRowLine.Split(new[] { "!" }, StringSplitOptions.RemoveEmptyEntries);

            var orderRow = new BaseOrderRow();

            //ProductCode
            {
                var str = words[0].Trim();
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }
                orderRow.ProductCode = str;
            }

            //ProductName
            {
                var str = words[1].Trim();
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }

                orderRow.ProductName = str;
            }

            //Count
            {
                var str = words[4].Trim();
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }

                orderRow.Count = decimal.Parse(str, RuCulture);
            }

            //UnitName
            {
                var str = words[8].Trim();
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }

                orderRow.UnitName = str;
            }


            return orderRow;
        }
    }
}
